﻿/*
 * Copyright 2008 Lucifer Lu
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */


using System.Reflection;
using System;
using SilverChart.Core.Configuration;
using System.Collections.Generic;
using SilverChart.Core.Service;

namespace SilverChart.Core {
    /// <summary>
    /// Each assembly have to have a class named AssemblyHelper, which implement this interface.
    /// The Loaded method in AssemblyHelper class will be invoked when the assembly has been processed by AppDomainHelper.
    /// This means all Services Points and Service Providers have been registed.
    /// </summary>
    public interface IAssemblyHelper {
        void Loaded(AppDomainHelper DomainHelper);
    }

    /// <summary>
    /// The AssemblyHelper in Core assembly. This class will listeren all assembly loaded event and process all Core service provider.
    /// </summary>
    class AssemblyHelper : IAssemblyHelper {
        //private static Logger logger = Logger.GetLogger<AssemblyHelper>();

        public AssemblyHelper() {
        }

        public void Loaded(AppDomainHelper DomainHelper) {
            DomainHelper.AssemblyLoaded += new AssemblyLoadedDelegate(OnAssemblyLoaded);
            DomainHelper.AllAssembliesHaveLoaded += new AllAssemlbiesHaveLoadedDelegate(AllAssembliesHaveLoaded);
        }

        void AllAssembliesHaveLoaded(object sender, EventArgs e) {
            //Logger logger = Logger.GetLogger<AssemblyHelper>();
            //logger.Debug("Registered Service:\n" + ServiceManager.Instance.ToString());
            ProcessConfigurations();
            //logger.Debug("Configuration Status:\n" + ServiceManager.Instance.GetService<ConfigurationService>().ToString());
        }

        void OnAssemblyLoaded(object sender, AssemblyLoadedEventArg e) {
            //logger.Debug(e.LoadedAssembly.FullName);
            Assembly assembly = e.LoadedAssembly;
            ProcessServices(assembly);
        }

        internal void ProcessFrameworkAssembly() {
            ProcessServices(this.GetType().Assembly);
        }

        private void ProcessServices(Assembly assembly) {
            Type[] typies = assembly.GetTypes();
            foreach (Type type in typies) {
                ProcessServicePoint(type);
                ProcessServiceProviders(type);
            }
        }

        private void ProcessServicePoint(Type type) {
            ServicePointAttribute servicePointAttribute = (ServicePointAttribute)Attribute.GetCustomAttribute(type, typeof(ServicePointAttribute));
            if (servicePointAttribute != null) {
                ServiceManager.Instance.AddServicePoint(type);
            }
        }

        private void ProcessServiceProviders(Type type) {
            ServiceProviderAttribute servicePointAttribute = (ServiceProviderAttribute)Attribute.GetCustomAttribute(type, typeof(ServiceProviderAttribute));
            if (servicePointAttribute != null) {
                ServiceManager.Instance.RegisteServcie(type, servicePointAttribute);
            }
        }

        private void ProcessConfigurations() {
            IList<Type> items = ServiceManager.Instance.GetServiceTypes<ConfigurationItem>();
            foreach (Type type in items) {
                ConfigurationItemAttribute configItemAttribute = (ConfigurationItemAttribute)Attribute.GetCustomAttribute(type, typeof(ConfigurationItemAttribute));
                if (configItemAttribute != null) {
                    ServiceManager.Instance.GetService<ConfigurationService>().AddConfigurationItem(configItemAttribute, type);
                }
            }
        }
    }
}
